package com.wfk.plat.aop;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.wfk.entity.SysMenus;
import com.wfk.entity.SysRoleMenu;
import com.wfk.entity.SysUser;
import com.wfk.plat.annotation.AuthResource;
import com.wfk.plat.mapping.MappingUtils;
import com.wfk.service.ISysMenusService;
import com.wfk.service.ISysRoleMenuService;
import com.wfk.service.ISysUserService;
import com.wfk.utils.FunctionUtils;

import cn.hutool.core.util.StrUtil;

@Aspect    //该标签把LoggerAspect类声明为一个切面
@Order(1)  //设置切面的优先级：如果有多个切面，可通过设置优先级控制切面的执行顺序（数值越小，优先级越高）
@Component //该标签把LoggerAspect类放到IOC容器中
public class ResourceAspect {
	
	@Autowired
	private ISysUserService sysUserService ;
	@Autowired
	private ISysMenusService sysMenusService ;
	@Autowired
	private ISysRoleMenuService sysRoleMenuService ;
	
	/**
	 * 定义一个方法，用于声明切入点表达式，方法中一般不需要添加其他代码
	 * 使用@Pointcut声明切入点表达式
	 * 后面的通知直接使用方法名来引用当前的切点表达式；如果是其他类使用，加上包名即可
	 */
	@Pointcut("@annotation(com.wfk.plat.annotation.AuthResource)")
	public void declearJoinPointExpression(){}

	/**
	 * 前置通知
	 * @param joinPoint
	 * @throws Throwable 
	 */
	@Before("declearJoinPointExpression()") //该标签声明次方法是一个前置通知：在目标方法开始之前执行
	@Around("declearJoinPointExpression()") //环绕表达式
	public Object beforMethod(ProceedingJoinPoint pjp) throws Throwable{
		ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		HttpServletResponse response = attributes.getResponse();
		// 拦截的实体类，就是当前正在执行的controller
		Object target = pjp.getTarget();
		// 拦截的方法名称。当前正在执行的方法
		String methodName = pjp.getSignature().getName();
		//拦截的方法参数类型
		Signature sig = pjp.getSignature();
		MethodSignature msig = null;
		if (!(sig instanceof MethodSignature)) {
			throw new IllegalArgumentException("该注解只能用于方法");
		}
		msig = (MethodSignature) sig;
		@SuppressWarnings("rawtypes")
		Class[] parameterTypes = msig.getMethod().getParameterTypes();
		Method method = null;
		try {
			method = target.getClass().getMethod(methodName, parameterTypes);
		} catch (NoSuchMethodException e1) {
			e1.printStackTrace();
		} catch (SecurityException e1) {
			e1.printStackTrace();
		}
		if (null != method) {
            if (method.isAnnotationPresent(AuthResource.class)) {
            	String url = request.getRequestURI() ;
            	AuthResource authResource = method.getAnnotation(AuthResource.class);
            	if(StrUtil.isNotBlank(authResource.url())) {
            		//如果url属性不为空
            		url = authResource.url() ;
            	}
            	Integer loginId = Integer.parseInt(request.getParameter("loginId"));
            	SysUser sysUser = sysUserService.getById(loginId);
            	SysRoleMenu sysRoleMenu = sysRoleMenuService.getByRoleid(sysUser.getRoleid()) ;
            	SysMenus sysMenus = sysMenusService.getByUrlAndId(url,FunctionUtils.getList(sysRoleMenu.getMenuids().split(","))) ;
            	if(sysMenus == null) {
            		//没有该菜单的权限不通行
            		response.sendRedirect(MappingUtils.error403);
            		return null ;
            	}
            	return pjp.proceed() ; //有权限继续往下执行
            }
        }
		return null ;
	}
}
